#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <wait.h>
#include <ctime>
#include "task.hpp"

using namespace std;

enum
{
    UserError = 1,
    subNumError,
    pipeError
};

void Usage(const string &str)
{
    cout << "Useage: " << str << " " << "sub_num_process" << endl;
}

class Channel
{
public:
    Channel(int wfd, pid_t sub_id, string &name)
        : _wfd(wfd), _sub_process_id(sub_id), _name(name)
    {
    }

    ~Channel()
    {
    }

    void Print() // 打印
    {
        cout << "_wfd: " << _wfd << " ";
        cout << "_sub_process_id: " << _sub_process_id << " ";
        cout << "_name: " << _name << endl;
    }
    string &getName()
    {
        return _name;
    }
    int getWfd()
    {
        return _wfd;
    }
    pid_t getPid()
    {
        return _sub_process_id;
    }
    void Close()
    {
        close(_wfd);
    }

private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    ProcessPool(int sub_number)
        : _sub_number(sub_number)
    {
    }
    //
    int CeateProcesss(work_t work) // 回调函数
    {
        vector<int> fds;
        for (int number = 0; number < _sub_number; number++)
        {
            int pipefd[2]{0};
            int n = pipe(pipefd); // 系统调用管道
            if (n < 0)
                return pipeError;

            pid_t id = fork();
            if (id == 0)
            {
                if (!fds.empty())
                {
                    cout << "close fd: ";
                    for (auto fd : fds)
                    {
                        close(fd); // 关闭开着的fd
                        cout << fd << " ";
                    }
                    cout << endl;
                }
                // 子进程r
                close(pipefd[1]); // 关闭注意别写成 close(1)
                // 子进程要完成的工作
                dup2(pipefd[0], 0); // 重定向到管道上，这样只需读0即可
                work(pipefd[0]);    // 执行任务
                exit(0);
            }
            // 父进程w
            close(pipefd[0]);
            string cname = "channel-" + to_string(number);
            channels.push_back(Channel(pipefd[1], id, cname)); // 自定义类型的类
            // 保存fd
            fds.push_back(pipefd[1]);
        }

        return 0;
    }

    int chanNext()
    {
        static int next = 0; // 只有一个
        // 轮询
        int c = next;
        next++;
        next %= channels.size();
        return c;
    }

    void Printdebug()
    {
        for (auto &chan : channels)
        {
            chan.Print(); // 打印
        }
    }

    void SendTaskCode(int index, uint32_t code)
    {
        cout << "sendcode: " << code << " to " << channels[index].getName()
             << " sub process id: " << channels[index].getPid() << endl;
        // 写
        write(channels[index].getWfd(), &code, sizeof(code));
        //    得到该管道的wfd
    }

    void KillAll() // 读端w关闭
    {
        for (auto &e : channels)
        {
            e.Close();
            pid_t pid = e.getPid();
            pid_t rid = waitpid(pid, nullptr, 0);
            if (rid == pid)
            {
                cout << "wait sub process: " << pid << " success.." << endl;
            }
            cout << e.getName() << " close done" << ", sub process quit now: " << e.getPid() << endl;
        }
    }
    void Wait()
    {
        // for(auto& e:channels)
        // {
        //     pid_t pid = e.getPid();
        //     pid_t rid = waitpid(pid, nullptr, 0);
        //     if(rid == pid)
        //     {
        //         cout<<"wait sub process: "<<pid<<" success.."<<endl;
        //     }
        // }
    }

    ~ProcessPool()
    {
    }

private:
    int _sub_number;
    vector<Channel> channels;
};

void CtrlProcesspool(ProcessPool *process_ptr, int cnt)
{
    while (cnt--)
    {
        // a、选择管道和子进程
        int c = process_ptr->chanNext(); // 获取选择的管道号码--第几个管道
        // cout<<c.getName()<<endl;

        // b、选择任务
        uint64_t code = commandNext(); // 获取选择的任务号码
        // c、发送任务
        process_ptr->SendTaskCode(c, code); // 给指定管道发送指定任务
        sleep(1);
    }
    cout << "run done!" << endl;
}

int main(int argc, char *argv[])
{
    // 格式为./myprocesspool 进程数量
    if (argc != 2)
    {
        Usage(argv[0]);
        return UserError;
    }
    int sub_number = stoi(argv[1]); // 转化为整型
    if (sub_number <= 0)
        return subNumError;

    srand((uint64_t)time(nullptr));
    // 1、创建多个管道和子进程
    ProcessPool *process_ptr = new ProcessPool(sub_number);
    process_ptr->CeateProcesss(worker);
    process_ptr->Printdebug();

    // 2、控制子进程
    CtrlProcesspool(process_ptr, 6);

    // sleep(100); // 100秒是为了方便用指令查看进程状态

    // 3、回收子进程

    // a.让所有子进程退出
    process_ptr->KillAll();
    // b.回收子进程资源
    // sleep(100);
    process_ptr->Wait();

    delete process_ptr;
    return 0;
}